'''
Author: kkk 997610780@qq.com
Date: 2025-02-28 16:13:39
LastEditors: kkk 997610780@qq.com
LastEditTime: 2025-03-06 14:29:40
FilePath: \get-video-images\app.py
Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
'''

# 在文件顶部的导入部分添加 json
from flask import Flask, request, jsonify, send_from_directory, Response
import os
import uuid
import json  # 添加这行
import cv2
from  douyin_video import get_video_url
from werkzeug.utils import secure_filename
from videoAction import image_ins_table,get_frame_images,extract_frames,download_video,get_video_url_from_share,extract_json_from_markdown,extract_markdown_table,process_table_data,convert_to_markdown_table,save_html_table,generate_clean_markdown_table,md2html_table,extract_frames_v2
from qianwen import analyze_video_frames,analyze_video_frames_v2,deepseek_r1
from pathlib import Path
from flask_cors import CORS
from uploadAliyunOss import upload_oss

# 在 Flask 初始化后添加CORS配置
app = Flask(__name__)
CORS(app)  # 允许所有域名访问

# 添加 JSON 配置，确保中文正常显示
app.config['JSON_AS_ASCII'] = False
app.json.ensure_ascii = False  # 添加这行配置


# 配置上传文件存储路径
UPLOAD_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'uploads')
if not os.path.exists(UPLOAD_FOLDER):
    os.makedirs(UPLOAD_FOLDER)



# UPLOAD_FOLDER = r'\\192.168.0.211\新盘\uploads'  # 使用 UNC 路径格式
# try:
#     if not os.path.exists(UPLOAD_FOLDER):
#         os.makedirs(UPLOAD_FOLDER)
#         print(f"创建网络共享文件夹成功: {UPLOAD_FOLDER}")
    
#     # 测试写入权限
#     test_file = os.path.join(UPLOAD_FOLDER, 'test.txt')
#     with open(test_file, 'w') as f:
#         f.write('test')
#     os.remove(test_file)
#     print("网络共享文件夹访问正常")
    
    
# except Exception as e:
#     print(f"无法访问网络共享文件夹: {str(e)}")
#     # 使用本地备用路径
#     UPLOAD_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'uploads')
#     if not os.path.exists(UPLOAD_FOLDER):
#         os.makedirs(UPLOAD_FOLDER)
#     print(f"已切换到本地备用路径: {UPLOAD_FOLDER}")

app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024  # 限制上传文件大小为100MB

# 允许的文件扩展名
ALLOWED_EXTENSIONS = {'mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv'}

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

# 添加上传图片接口

# 在 ALLOWED_EXTENSIONS 定义后添加图片允许的扩展名
ALLOWED_IMAGE_EXTENSIONS = {'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'}

# 在 allowed_file 函数后添加新的函数
def allowed_image(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_IMAGE_EXTENSIONS

# 添加新的上传图片接口
@app.route('/upload/image', methods=['POST'])
def upload_image():
    """
    上传图片接口：接受图片文件并保存
    """
    try:
        # 检查是否有文件上传
        if 'file' in request.files:
            file = request.files['file']
            
            # 如果用户没有选择文件，浏览器也会提交一个空的文件部分
            if file.filename == '':
                return jsonify({'error': '没有选择文件'}), 400
            
            if file and allowed_image(file.filename):
                # 安全地获取文件名并保存文件
                filename = secure_filename(file.filename)
                # 添加唯一标识符，避免文件名冲突
                unique_filename = f"{uuid.uuid4().hex}_{filename}"
                file_path = os.path.join(app.config['UPLOAD_FOLDER'], unique_filename)
                file.save(file_path)
                
                return jsonify({
                    'success': True,
                    'message': '图片上传成功',
                    'file_path': file_path,
                    'filename': unique_filename
                })
            
            return jsonify({'error': '不允许的文件类型'}), 400
        
        else:
            return jsonify({'error': '请提供图片文件'}), 400
            
    except Exception as e:
        return jsonify({'error': f'上传图片时出错: {str(e)}'}), 500

@app.route('/upload', methods=['POST'])
def upload_video():
    """
    上传视频接口：接受视频文件上传并处理
    """
    try:
        # 检查是否有文件上传
        if 'file' in request.files:
            file = request.files['file']
            
            # 如果用户没有选择文件，浏览器也会提交一个空的文件部分
            if file.filename == '':
                return jsonify({'error': '没有选择文件'}), 400
            
            if file and allowed_file(file.filename):
                # 安全地获取文件名并保存文件
                filename = secure_filename(file.filename)
                # 添加唯一标识符，避file_path免文件名冲突
                unique_filename = f"{uuid.uuid4().hex}_{filename}"
                file_path = os.path.join(app.config['UPLOAD_FOLDER'], unique_filename)
                
                file.save(file_path)
                
                # 处理视频，提取帧
                output_dir = extract_frames(file_path,True)
                
                # 处理完成后删除上传的视频文件
                if os.path.exists(file_path):
                    os.remove(file_path)
                
                return jsonify({
                    'success': True,
                    'message': '视频处理成功',
                    'output_directory': output_dir
                })
            
            return jsonify({'error': '不允许的文件类型'}), 400
        
        else:
            return jsonify({'error': '请提供视频文件'}), 400
            
    except Exception as e:
        return jsonify({'error': f'处理视频时出错: {str(e)}'}), 500

@app.route('/frames/<path:folder_name>/<path:filename>', methods=['GET'])
def get_frame(folder_name, filename):
    """获取处理后的视频帧图片"""
    try:
        frames_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "frames")
        response = send_from_directory(os.path.join(frames_dir, folder_name), filename)
        
        # 设置响应头
        response.headers['Cache-Control'] = 'public, max-age=31536000'  # 缓存一年
        response.headers['Access-Control-Allow-Origin'] = '*'  # 允许跨域访问
        response.headers['Access-Control-Allow-Methods'] = 'GET'
        response.headers['X-Content-Type-Options'] = 'nosniff'  # 防止浏览器猜测内容类型
        response.headers['Content-Security-Policy'] = "default-src 'self'"  # 内容安全策略
        
        return response
    except Exception as e:
        return jsonify({'error': f'获取图片失败: {str(e)}'}), 404

# 新增访问上传文件夹视频的路由
@app.route('/uploads/<path:filename>', methods=['GET'])
def get_video(filename):
    """获取上传文件夹中的视频文件"""
    try:
        return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
    except Exception as e:
        return jsonify({'error': f'获取视频文件失败: {str(e)}'}), 404

@app.route('/tables/<path:filename>', methods=['GET'])
def get_table_file(filename):
    """获取tables文件夹中的HTML文件"""
    try:
        tables_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "tables")
        response = send_from_directory(tables_dir, filename)
        
        # 设置响应头
        response.headers['Cache-Control'] = 'public, max-age=3600'  # 缓存一小时
        response.headers['Access-Control-Allow-Origin'] = '*'  # 允许跨域访问
        response.headers['Access-Control-Allow-Methods'] = 'GET'
        response.headers['Content-Type'] = 'text/html; charset=utf-8'  # 确保HTML正确显示
        
        return response
    except Exception as e:
        return jsonify({'error': f'获取HTML文件失败: {str(e)}'}), 404

@app.route('/health', methods=['GET'])
def health_check():
    return jsonify({'status': 'ok'})


def download_from_url(data,fps = 30,isBase64 = False,oss = True):
    """
    通过抖音视频链接下载视频并处理
    """
    try:
        video_url = data['url']
        # 如果是分享链接，先获取实际视频地址
        if 'v.douyin.com' in video_url or 'www.douyin.com' in video_url:
            real_video_url = get_video_url_from_share(video_url)
            if not real_video_url:
                return jsonify({'error': '无法获取视频地址'}), 400
            video_url = real_video_url
        
        # 下载视频
        video_filename = f"{uuid.uuid4().hex}.mp4"
        video_path = os.path.join(app.config['UPLOAD_FOLDER'], video_filename)
        print('正在下载视频到网络位置:', video_path)

        # 确保网络文件夹存在
        if not os.path.exists(app.config['UPLOAD_FOLDER']):
            os.makedirs(app.config['UPLOAD_FOLDER'])
        # 下载视频
        if not download_video(video_url, video_path):
            return jsonify({'error': '视频下载失败'}), 400
        # 验证文件是否成功保存
        if not os.path.exists(video_path):
            return jsonify({'error': '视频保存失败'}), 500

        
        # 获取视频时长
        cap = cv2.VideoCapture(video_path)
        total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
        video_fps = cap.get(cv2.CAP_PROP_FPS)
        duration = total_frames / video_fps  # 视频总时长（秒）
        cap.release()
        print(f'111视频帧数: {fps} 视频帧率: {video_fps}')
        if  fps < video_fps:
            # 处理视频，提取帧
            output_dir = extract_frames_v2(video_path,isBase64,fps,oss)
        else:
            output_dir = extract_frames(video_path,isBase64,video_fps,oss)

        if oss:
            video_remoth_url = upload_oss(video_url,'uploads/'+video_filename)
            os.remove(video_path)

        return jsonify({
            'success': True,
            'message': '视频处理成功',
            'video_path': video_remoth_url,  # 返回视频路径
            'output_directory': output_dir,
            'duration': round(duration, 2),  # 返回视频时长（四舍五入到2位小数）
            'total_frames': total_frames,  # 返回总帧数
            'video_fps': video_fps  # 返回视频帧率
        })

    except Exception as e:
        print(f"错误详情: {str(e)}")  # 添加详细错误日志
        return jsonify({'error': f'处理视频时出错: {str(e)}'}), 500

@app.route('/analyze', methods=['POST'])
def analyze_video():
    """
    分析视频帧并生成分镜脚本
    """
    try:
        # 检查Content-Type
        if not request.is_json:
            return jsonify({
                'error': '请求格式错误',
                'detail': f'当前Content-Type: {request.content_type}, 需要: application/json'
            }), 415
            
        data = request.get_json(silent=True)
        if data is None:
            return jsonify({
                'error': '无效的JSON数据',
                'detail': '请确保请求体是有效的JSON格式'
            }), 400
            
        if 'url' not in data:
            return jsonify({'error': '请提供视频链接'}), 400

        
        videos = get_video_url(data['url'])
        # 先调用download_from_url获取图片列表
        download_response = download_from_url({'url': videos[0]})
        if download_response.status_code != 200:
            return download_response
        download_data = download_response.get_json()
  
        if not download_data.get('success'):
            return jsonify({'error': '获取视频帧失败'}), 500
        output_directory =  download_data.get('output_directory')
        image_list = output_directory['image_paths']
        result = analyze_video_frames(image_list)

        # output_dir = extract_frames(download_data.get('video_path'))
        headers, table_data = extract_markdown_table(result)
        headers.insert(0, '切片')
        data = process_table_data(table_data,image_list)
        # print('生成表格数据',headers,list)
        html_file_path = save_html_table(headers,data)
        response = jsonify({
            'success': True,
            'message': '分析成功',
            'result': convert_to_markdown_table(headers,data),
            'html_file_path': html_file_path,
            'headers':headers,
            'table_data':table_data
        })
        response.headers['Content-Type'] = 'application/json; charset=utf-8'
        # 不需要手动添加CORS头，因为flask-cors会自动处理
        return response
            
    except Exception as e:
        print(f"错误详情: {str(e)}")
        return jsonify({'error': f'分析视频时出错: {str(e)}'}), 500


@app.route('/analyze_v2', methods=['POST'])
def analyze_video_v2():
    """
    分析视频帧并生成分镜脚本
    """
    try:
        # 检查Content-Type
        if not request.is_json:
            return jsonify({
                'error': '请求格式错误',
                'detail': f'当前Content-Type: {request.content_type}, 需要: application/json'
            }), 415
            
        data = request.get_json(silent=True)
        if data is None:
            return jsonify({
                'error': '无效的JSON数据',
                'detail': '请确保请求体是有效的JSON格式'
            }), 400
            
        if 'url' not in data:
            return jsonify({'error': '请提供视频链接'}), 400

        
        videos = get_video_url(data['url'])
        # 每秒截取图片的帧率
        fps = 1
        # 先调用download_from_url获取图片列表
        download_response = download_from_url({'url': videos[0]},fps,False)
        if download_response.status_code != 200:
            return download_response
            
        download_data = download_response.get_json()
        duration = download_data.get('duration')
        # print(f'视频时长{download_data.get('duration')},总帧数:{download_data.get('total_frames')}')
        if not download_data.get('success'):
            return jsonify({'error': '获取视频帧失败'}), 500
            
        imageResult = download_data.get('output_directory')
        image_paths = imageResult['image_paths']
        print('视频链接',download_data['video_path'])
        folder_name = imageResult['folder_name']
        # 使用base64编码后的图片列表
        # image_base64_list = get_frame_images(folder_name)
        
        # 使用map函数过滤数组，只返回path字段
        def extract_path(item):
            return item['path'] if isinstance(item, dict) and 'path' in item else None
        image_list = list(filter(None, map(extract_path, imageResult['image_paths'])))


        result = analyze_video_frames_v2(download_data['video_path'],duration)

        headers, table_data = extract_markdown_table(result)

        headers.insert(0, '切片')
        data = image_ins_table(table_data,image_list)

        response = jsonify({
            'success': True,
            'message': '分析成功',
            'result': result,
            # 'html_file_path': html_file_path,
            'headers':headers,
            'table_data':data,
            # 'images':output_dir,
            'folder_name':folder_name
        })
        response.headers['Content-Type'] = 'application/json; charset=utf-8'
        return response
            
    except Exception as e:
        print(f"错误详情: {str(e)}")
        return jsonify({'error': f'分析视频时出错: {str(e)}'}), 500


@app.route('/script_create', methods=['POST'])
def script_create():
    try:
        if not request.is_json:
            return jsonify({'error': '请求格式错误'}), 415
            
        data = request.get_json(silent=True)
        if not data:
            return jsonify({'error': '无效的JSON数据'}), 400

        def generate():
            for chunk in deepseek_r1(data.get('content', ''), stream=True):
                yield f"data: {json.dumps(chunk, ensure_ascii=False)}\n\n"

        return Response(generate(), mimetype='text/event-stream')
            
    except Exception as e:
        return jsonify({'error': f'处理失败: {str(e)}'}), 500




if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=True)
